package cn.ante.basic.interceptor;

import cn.ante.basic.annotation.PreAuthorize;
import cn.ante.basic.jwt.JwtUtils;
import cn.ante.basic.jwt.Payload;
import cn.ante.basic.jwt.RsaUtils;
import cn.ante.basic.jwt.UserInfo;
import cn.ante.system.mapper.PermissionMapper;
import cn.ante.user.domain.Logininfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.security.PublicKey;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class LoginInterceptor implements HandlerInterceptor {
//    @Autowired
//    private RedisTemplate redisTemplate;
//
//    @Autowired
//    private PermissionMapper permissionMapper;

    @Value("${jwt.rsa.pub}")
    private String jwtRsapublic;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        System.out.println("获取前端传过来的token 444444444444444444444");
        // 设置编码字符集,设置响应参数为json格式
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=UTF-8");
        // 获取前端请求头中的token
        String token = request.getHeader("token");
        //=========================以下是redis方案
        // 判断前端请求是否携带token,如果携带就进入判断
        //当token不为空的时候，表示token存在，就拿出token的value,在判断value是否为空，不为空就刷新token有效期
        if (!StringUtils.isEmpty(token)){
//            Object logininfo = redisTemplate.opsForValue().get(token);
//            if (logininfo != null){
//                // 当logininfo不为空的时候，将其拷贝到临时对象，因为logininfo是一个任意对象
//                Logininfo logininfoTmp = new Logininfo();
//                BeanUtils.copyProperties(logininfo,logininfoTmp);
//
//                // 判断登录用户是否是后台员工
//                if (logininfoTmp.getType() == 0){
//
//                  // 拿到此前员工请求的接口路径，先得到本次请求的方法对象，从方法对象中获取到自定义注解
//                    HandlerMethod handlerMethod =  (HandlerMethod) handler;
//                    PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
//                   // 当注解为空，表示访问的公共资源，不需要进行拦截，当不为空的时候，需要与该角色的权限进项对比
//                    if (preAuthorize != null){
//                        // 获取到该员工所对应的角色的所有权限
//                        List<String>  sns = permissionMapper.loadOwnPermissionByLogininfoId(logininfoTmp.getId());
//                        // 从自定义注解对象中拿到本次访问的权限编码
//                        String sn = preAuthorize.sn();
//                        // 判断此权限的编码是否包含在该员工角色的所有权限中
//                        if (!sns.contains(sn)){
//                            // 如果不包含就返回给前端一个响应消息，并拦截
//                            // 获取打印流，并设置响应数据,响应的打印输出六使用时，需要每使用一次就是获取一次
//                            PrintWriter writer = response.getWriter();
//                            writer.println("{\"success\":false,\"resultObj\":\"noPermission\"}");
//                            writer.flush();;
//                            writer.close();
//                            return false;
//                        }
//                    }
//
//                }
//
//                redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
//                return true;
//            }

        // 以上条件都不满足的时候就执行未登录处理
        // 获取打印流，并设置响应数据
        // 以下是jwt方案
        // 使用jwt的工具拿到公钥
            PublicKey publicKey = RsaUtils.getPublicKey(JwtUtils.class.getClassLoader().getResource(jwtRsapublic).getFile());
        // 对jwt字符串解密,得到载荷对象
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, publicKey, UserInfo.class);
        // 对拿到的载荷对象进行判断
        if (payload != null){
            // 不为空就将userinfo对象拿出来
            UserInfo userInfo = payload.getUserInfo();
            // 得到登录dlogininfo对象
            Logininfo logininfo = userInfo.getLogininfo();
            // 判断登录对象是否是后台人员
            if (logininfo.getType() == 0){
                // 得到本次请求的方法对象
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                // 从方法对象中的到指定注解
                PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                // 判断方法上是否有此注解，如果没有说明是公共资源
                if(preAuthorize != null){
                    // 从注解中获取到sn值，也就是本次请求对应的权限编码，用于判断用户是否有此URL权限
                    String permissionSn = preAuthorize.sn();
                    // 获取到用户所拥有的所有权限,这一句不应该出现再这里，应该再登录的时候将其放在redis中
                    // List<String> ownPermissions = permissionMapper.loadOwnPermissionByLogininId(logininfoTmp.getId());
                    // 直接从JWT解析出来的对象中获取用户权限集合
                    if (!userInfo.getPermissions().contains(permissionSn)) {
                        // 员工所有的权限不包含访问的权限，那么直接设置响应信息并拦截
                        PrintWriter writer = response.getWriter();
                        writer.write("{\"success\":false,\"resultObj\":\"noPermission\"}");
                        writer.flush();
                        writer.close();
                        return false;
                    }
                    }
                }
                 return true;
            }
        }
        // 如果能走到这里，说明token为空或者是Redis中用户信息为空，那么以未登录进行处理
        // 获取到打印流,并设置响应数据
        PrintWriter writer = response.getWriter();
        writer.write("{\"success\":false,\"resultObj\":\"noLogin\"}");
        // 刷新、关流
        writer.flush();
        writer.close();
        return false;
    }
}

